package com.iwhalecloud.bss.kite.cucc.web.service.goods.modify.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import com.iwhalecloud.bss.kite.cucc.service.addRoleProdDeal.AddRoleProdFactory;
import com.iwhalecloud.bss.kite.cucc.service.addRoleProdDeal.IAddRoleProdService;
import com.iwhalecloud.bss.kite.cucc.web.service.ISceneService;
import com.iwhalecloud.bss.kite.manager.dto.KiteAttrDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.goods.IGoodsModifyService;
import com.iwhalecloud.bss.kite.cucc.client.api.order.ICommonSevice;
import com.iwhalecloud.bss.kite.cucc.client.api.order.IOrderService;
import com.iwhalecloud.bss.kite.cucc.client.api.scene.IInitSceneOfferInstService;
import com.iwhalecloud.bss.kite.cucc.client.dto.cust.CuccContextCustDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.goods.AttrDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.goods.GoodsDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.goods.modify.request.AbstractCreateGoodsModifySceneRequest;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosCustomerDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosUserDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.scene.CuccCustInfoDTO;
import com.iwhalecloud.bss.kite.cucc.manager.inst.CuccKiteOfferInstAcct;
import com.iwhalecloud.bss.kite.dataservice.util.IdUtils;
import com.iwhalecloud.bss.kite.event.offer.InitMainOfferEvent;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQueryInstTemplateService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.dto.KiteInstRelDTO;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.enums.RelType;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstAcct;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstContract;
import com.iwhalecloud.bss.kite.manager.inst.KiteSceneInst;
import com.iwhalecloud.bss.kite.manager.util.ManagerUtils;
import com.iwhalecloud.bss.kite.service.inf.accept.kitexchange.handler.AcceptScalpelUtil;
import com.iwhalecloud.bss.kite.service.scene.bo.OperateSceneOfferInstBO;
import com.iwhalecloud.bss.kite.web.context.KiteWebContext;
import com.ztesoft.bss.common.bo.LoginInfo;
import com.ztesoft.bss.common.util.ContextUtil;

/**
 * 商品变更业务处理抽象类
 * 核心功能:查询可变更套餐列表、商品变更场景初始化、场景还原以及实例动作处理
 * 需要新增时如果是通用功能考虑在接口里增加
 */
public abstract class AbstractGoodsModifyService implements IGoodsModifyService {

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IQuerySceneInstService querySceneInstService;

    @Autowired
    private IQueryInstTemplateService queryInstTemplateService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ISceneService sceneService;

    @Autowired
    private IOperateSceneInstService operateSceneInstService;

    @Autowired
    private OperateSceneOfferInstBO operateSceneOfferInstBO;

    @Autowired
    private IInitSceneOfferInstService initSceneOfferInstService;

    @Autowired
    private ICommonSevice commonService;

    /**
     * 获取可以变更的目标套餐集合,由子类按不同商品分类重写
     * @param offerId
     * @param cateId
     * @return
     */
    @Override
    public List<GoodsDTO> queryTargetGoodsList(String offerId, String cateId) {
        return new ArrayList<>();
    }

    /**
     * 获取关键属性列表,待后续需求提供公共逻辑后补充,特殊的商品类别逻辑可由对应子类重写
     * @param goodsSku
     * @return
     */
    @Override
    public List<AttrDTO> queryGoodKeyAttrs(String goodsSku) {
        return new ArrayList<>();
    }

    /**
     * 创建商品变更场景方法
     * 1、负责场景初始化以及将原套餐的实例动作置为D
     * 2、支持场景初始化逻辑扩展
     * 3、处理原套餐实例动作目前主要针对付费关系、合同、折扣以及产品销售品,需要增加某些对象的处理请尽量先在抽象类添加
     * 4、如某类产品需要特殊处理,可在子类中扩展
     * @param request
     * @return
     */
    @Override
    public String createGoodsModifyScene(AbstractCreateGoodsModifySceneRequest request) {
        LoginInfo loginInfo = ContextUtil.getLoginInfo();
        String provinceId = loginInfo.getUserInfo().getPostProvinceNbr();
        String lanId = loginInfo.getUserInfo().getPostLanId();
        String staffCode = (String) ContextUtil.getLoginInfo().getUserInfo().getExtParams().get("account");
        //1、调用变更单接口
        Map<String, Object> infResult = orderService.getChangeOriginOrder("", request.getCustId(), request.getSerialNumber(), provinceId, lanId, staffCode, "");
        KitePosDTO kitePosDTO = JSONObject.toJavaObject(JSON.parseObject(JSON.toJSONString(infResult)), KitePosDTO.class);
        //2、客户信息
        this.initContext(kitePosDTO.getCustomer());
        String custId = KiteWebContext.getContext().getCustId();
        //3、场景初始化
        String sceneInstId = createModifyOfferScene(request, custId, KiteWebContext.getContext().getCust().getCustName(), kitePosDTO);
        //4、场景还原
        restoreSceneInst(sceneInstId, request, kitePosDTO);
        //5、如果是录入环节,需要处理新旧套餐的实例动作
        String nodeCode = querySceneInstService.getExtParameterValue(sceneInstId, "nodeCode");
        if (KiteStringUtils.isEmpty(nodeCode)) {
            //还原实例
            List<KitePosGoodsDTO> offerInsts = kitePosDTO.getGoods();

            List<KitePosGoodsDTO> oldPosGoods = offerInsts.stream().filter(posGoods -> !request.getTargetOfferId().equals(posGoods.getCode()))
                .collect(Collectors.toList());
            //5.1、处理付费关系
            dealOfferInstAcctActionType(sceneInstId, request, oldPosGoods, custId);
            //5.2、处理合同
            dealOfferInstContractActionType(sceneInstId, request, oldPosGoods, custId);
            //5.3、处理折扣信息
            dealOfferInstDiscountActionType(sceneInstId, request, oldPosGoods, custId);
            //5.4、处理产品
            dealProductActionType(sceneInstId, request, oldPosGoods, custId);
            //5.5、处理原套餐
            dealMainOfferInstActionType(sceneInstId, request, oldPosGoods, custId);
        }
        // 用户信息不变
        this.operateSceneInstService.putExtParameter(sceneInstId, "serialNumber", kitePosDTO.getUsers());

        return sceneInstId;
    }

    public String createModifyOfferScene(AbstractCreateGoodsModifySceneRequest request, String custId, String custName, KitePosDTO kitePosDTO) {
        //1、场景初始化
        String sceneInstId = createOfferScene(request, custId, custName, kitePosDTO);
        //2、回填关键属性
        if (KiteListUtils.isNotEmpty(request.getKeyAttrs())) {
            List<KiteAttrDTO> attrs = request.getKeyAttrs();
            this.sceneService.updateInstAttr(sceneInstId, attrs,
                querySceneInstService.listMainOfferInsts(sceneInstId).stream()
                    .filter(KiteOfferInst -> KiteOfferInst.getOfferId().equals(request.getTargetOfferId()))
                    .findFirst().orElse(null).getOfferInstId());
        }
        //3、原套餐实例化,设置界面不展示
        Set<String> hideInsts = Optional.ofNullable(querySceneInstService.getSceneInst(sceneInstId).getHideInsts()).orElse(new HashSet<>());
        kitePosDTO.getGoods().stream()
            .filter(good -> !request.getTargetOfferId().equals(good.getCode())).findAny().ifPresent(good -> {
            KiteOfferInst offerInst = addOfferInst(sceneInstId, good.getCode(), InstType.MAIN_OFFER_INST, custId, request.getStaffId());
            hideInsts.add(ManagerUtils.join(offerInst.getInstType(), offerInst.getOfferInstId()));
        });
        querySceneInstService.getSceneInst(sceneInstId).setHideInsts(hideInsts);
        //4、场景初始化后处理
        afterInitSceneInst(sceneInstId, request, custId, kitePosDTO);
        return sceneInstId;
    }


    /**
     * 场景初始化,提供给子类扩展
     * @param request
     * @param custId
     * @param custName
     * @param kitePosDTO
     * @return
     */
    public abstract String createOfferScene(AbstractCreateGoodsModifySceneRequest request, String custId, String custName, KitePosDTO kitePosDTO);

    /**
     * 场景初始化后处理
     * @param sceneInstId
     * @param request
     * @param custId
     * @param kitePosDTO
     */
    public void afterInitSceneInst(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, String custId, KitePosDTO kitePosDTO) {

    };


    public void dealOfferInstAcctActionType(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, List<KitePosGoodsDTO> oldPosGoods, String custId){
        String offerInstId = querySceneInstService.getSceneInst(sceneInstId).getRootInstId();
        KiteOfferInst offerInst = querySceneInstService.getOfferInst(custId, offerInstId);
        for (KitePosGoodsDTO goods : oldPosGoods) {
            String oldOfferId = goods.getCode();
            List<KiteOfferInst> oldOfferInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, oldOfferId);
            if (KiteListUtils.isNotEmpty(oldOfferInsts)) {
                KiteOfferInst oldOfferInst = oldOfferInsts.get(0);
                //处理付费关系,把原有的复制一个挂到目标套餐下,旧的置为D
                List<KiteOfferInstAcct> oldAccts = querySceneInstService.listOfferInstAccts(custId, oldOfferInst.getOfferInstId());
                oldAccts.forEach(oldAcct -> {
                    CuccKiteOfferInstAcct acct = new CuccKiteOfferInstAcct();
                    KiteBeanUtils.copyProperties(oldAcct, acct, "actionType", "offerName", "offerInstId", "instId");
                    acct.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                    acct.setOfferInstId(offerInstId);
                    acct.setOfferName(offerInst.getOfferName());
                    acct.setActionType(ActionType.A);
                    operateSceneInstService.addOfferInstAcct(sceneInstId, acct, acct.getOfferInstId(), RelType.OFFER_OBJ_REL_TYPE_170000, ActionType.A, KeyConsts.OFFER_ACCOUNT_ROLE, request.getTargetOfferId());
                    operateSceneInstService.deleteOfferInstAcct(sceneInstId, oldAcct.getInstId());
                });
            }
        }
    };

    public void dealOfferInstContractActionType(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, List<KitePosGoodsDTO> oldPosGoods, String custId){
        String offerInstId = querySceneInstService.getSceneInst(sceneInstId).getRootInstId();
        for (KitePosGoodsDTO goods : oldPosGoods) {
            String oldOfferId = goods.getCode();
            List<KiteOfferInst> oldOfferInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, oldOfferId);
            if (KiteListUtils.isNotEmpty(oldOfferInsts)) {
                KiteOfferInst oldOfferInst = oldOfferInsts.get(0);
                //处理合同,把原有的复制一个挂到目标套餐下,旧的置为D
                List<KiteOfferInstContract> oldContracts = querySceneInstService.listOfferInstContracts(custId, oldOfferInst.getOfferInstId());
                oldContracts.forEach(oldContract -> {
                    KiteOfferInstContract offerInstContractRel = new KiteOfferInstContract();
                    KiteBeanUtils.copyProperties(oldContract, offerInstContractRel, "actionType", "offerInstId", "instId");
                    offerInstContractRel.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                    offerInstContractRel.setOfferInstId(offerInstId);
                    offerInstContractRel.setActionType(ActionType.A);
                    operateSceneInstService.addOfferInstContract(sceneInstId, offerInstContractRel, offerInstContractRel.getOfferInstId(), RelType.OFFER_OBJ_REL_TYPE_190000, ActionType.K, KeyConsts.OFFER_CONTRACT_ROLE, request.getTargetOfferId());
                    operateSceneInstService.deleteOfferInstContract(sceneInstId, oldContract.getInstId());
                });
            }
        }
    };

    public void dealOfferInstDiscountActionType(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, List<KitePosGoodsDTO> oldPosGoods, String custId){

    };

    public void dealProductActionType(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, List<KitePosGoodsDTO> oldPosGoods, String custId){
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        for (KitePosGoodsDTO goods : oldPosGoods) {
            String oldOfferId = goods.getCode();
            List<KiteOfferInst> oldOfferInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, oldOfferId);
            if (KiteListUtils.isNotEmpty(oldOfferInsts)) {
                KiteOfferInst oldOfferInst = oldOfferInsts.get(0);
                //处理产品
                List<KiteInstRelDTO> instRels = this.querySceneInstService.listInstRelsByAInst(custId, InstType.MAIN_OFFER_INST, oldOfferInst.getOfferInstId(), InstType.PROD_INST);
                String prodInstId = instRels.get(0).getzInstId();
                operateSceneInstService.deleteProdInst(sceneInstId, prodInstId);
            }
        }
    };

    public void dealMainOfferInstActionType(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, List<KitePosGoodsDTO> oldPosGoods, String custId){
        for (KitePosGoodsDTO goods : oldPosGoods) {
            String oldOfferId = goods.getCode();
            List<KiteOfferInst> oldOfferInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, oldOfferId);
            if (KiteListUtils.isNotEmpty(oldOfferInsts)) {
                KiteOfferInst oldOfferInst = oldOfferInsts.get(0);
                //处理销售品
                operateSceneInstService.deleteMainOfferInst(sceneInstId, oldOfferInst.getOfferInstId());
//                operateChangeService.setDeleteInstChange(sceneInst, oldOfferInst, false, null, "");
//                oldOfferInst.setActionType(ActionType.D);
//                oldOfferInst.setOriginalActionType(ActionType.K);
//                // 设备类增加创建时间
//                try {
//                    oldOfferInst.setCreateDate(DateUtils.parseStrToDate(goods.getStartDate(), DateUtils.longPattern));
//                } catch (Exception e) {
//                    // 异常不需要处理
//                }
//                operateSceneInstService.addInst(sceneInstId, oldOfferInst);
            }
        }
    };

    @Override
    public void restoreSceneInst(String sceneInstId, AbstractCreateGoodsModifySceneRequest request, KitePosDTO kitePosDTO) {
        String custId = KiteWebContext.getContext().getCustId();
        LoginInfo loginInfo = ContextUtil.getLoginInfo();
        String staffId = loginInfo.getUserInfo().getUserId() + "";
        //还原实例
        List<KitePosGoodsDTO> offerInsts = kitePosDTO.getGoods();
        this.initSerialNumberCommonAttr(sceneInstId, kitePosDTO);
        this.initSceneOfferInstService.initMainOfferInst(sceneInstId, custId, request.getStaffId(), offerInsts, loginInfo);
        IAddRoleProdService addRoleProdService = AddRoleProdFactory.getRoleProdSupplier(request.getCateId());
        if (Objects.isNull(addRoleProdService)) {
            this.initSceneOfferInstService.initAddRoleOfferInst(sceneInstId, custId, staffId, offerInsts, loginInfo);
        }
        else {
            addRoleProdService.initAddRoleOfferInst(sceneInstId, custId, staffId, offerInsts);
        }
        this.initSceneOfferInstService.initAdditionalOfferInst(sceneInstId, custId, staffId, offerInsts, loginInfo);
        this.initSceneOfferInstService.initOfferInstAcct(sceneInstId, null, custId, kitePosDTO, loginInfo);
        this.initSceneOfferInstService.initOfferInstContract(sceneInstId, null, custId, kitePosDTO, loginInfo);
        this.initSceneOfferInstService.initOfferInstDiscount(sceneInstId, null, custId, kitePosDTO, loginInfo);
        commonService.initCommonAttrValues(sceneInstId, request.getServiceOfferId(), request.getCustId(), kitePosDTO, loginInfo);
    }


    private void initContext(KitePosCustomerDTO customer) {
        CuccCustInfoDTO cuccCustInfoDTO = KiteBeanUtils.transform(customer, CuccCustInfoDTO.class);
        CuccContextCustDTO contextCust = new CuccContextCustDTO();
        if (Objects.nonNull(cuccCustInfoDTO)) {
            KiteBeanUtils.copyProperties(cuccCustInfoDTO, contextCust);
            //集团客户名称
            contextCust.setProvinceCode(cuccCustInfoDTO.getEparchyProvince());
            contextCust.setCustName(cuccCustInfoDTO.getName());
            contextCust.setLanId(cuccCustInfoDTO.getEparchyCity());
            contextCust.setEparchyCode(cuccCustInfoDTO.getEparchyCity());
            contextCust.setRegionId(cuccCustInfoDTO.getEparchyArea());
            contextCust.setAttrs(cuccCustInfoDTO.getAttrs());
        }
        KiteWebContext.initContext(KiteWebContext.getKiteContextId(), contextCust);
    }

    private void initSerialNumberCommonAttr(String sceneInstId, KitePosDTO kitePosDTO) {
        if (!KiteListUtils.isEmpty(kitePosDTO.getRelations())) {
            String serialNumber = kitePosDTO.getRelations().get(0).getPrimarySerialNumber();
            commonService.setCommonAttrValue(sceneInstId, "business_number", serialNumber, serialNumber, serialNumber);
        }
        else {
            // 业务号码回填
            List<KitePosUserDTO> users = kitePosDTO.getUsers();
            if (!KiteListUtils.isEmpty(users)) {
                commonService
                    .setCommonAttrValue(sceneInstId, "business_number", kitePosDTO.getUsers().get(0).getSerialNumber(),
                        kitePosDTO.getUsers().get(0).getSerialNumber(), kitePosDTO.getUsers().get(0).getSerialNumber());
            }
        }
        if (!KiteObjectUtils.isEmpty(kitePosDTO) && KiteListUtils.isNotEmpty(kitePosDTO.getUsers())) {
            commonService.setCommonAttrValue(sceneInstId, "group_user_name", kitePosDTO.getUsers().get(0).getName(),
                kitePosDTO.getUsers().get(0).getName(), kitePosDTO.getUsers().get(0).getName());
        }
    }

    /**
     * 添加原套餐实例到场景中
     * @param sceneInstId
     * @param newOfferId
     * @param instType
     * @param custId
     * @param staffId
     * @return
     */
    private KiteOfferInst addOfferInst(String sceneInstId, String newOfferId, InstType instType, String custId, String staffId) {
        String regionCode = ContextUtil.getLoginInfo().getUserInfo().getPostProvinceNbr();
        KiteOfferInst offerInst = queryInstTemplateService.getOfferInst(newOfferId, regionCode);
        // 判断实例模版是否存在
        if (offerInst == null) {
            /** 初始化模版实例对象 **/
            offerInst = operateSceneOfferInstBO.initKiteOfferInst(newOfferId, custId, instType, regionCode);
        }

        AcceptScalpelUtil.replaceInstId(offerInst, null);
        offerInst.setActionType(ActionType.A);
        if (Objects.equals(instType, InstType.MAIN_OFFER_INST)) {
            operateSceneInstService.addMainOfferInst(sceneInstId, offerInst);
        }
        else {
            operateSceneInstService.addPromotionOfferInst(sceneInstId, offerInst);
        }

        InitMainOfferEvent initMainOfferEvent = new InitMainOfferEvent(this, custId, staffId);
        initMainOfferEvent.setOfferId(newOfferId);
        initMainOfferEvent.setParentInstId(offerInst.getOfferInstId());
        initMainOfferEvent.setSceneInstId(sceneInstId);
        initMainOfferEvent.setDetailIds(null);
        applicationContext.publishEvent(initMainOfferEvent);

        return offerInst;
    }
}
